package model;

import java.util.Collections;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

public class ConfirmMonitor {

	private final static double variableDeadlockPercent = 0.5;
	private final static int fixedNumOfUnblockedUsers = 1;
	private boolean variableFixed = false; // true if variable, false if fixed
	private static ConfirmMonitor instance = null;
	private List<User> blockedUsers;

	// private Constructor: cannot be instantiated from outside.
	private ConfirmMonitor() {
		this.blockedUsers = Collections
				.synchronizedList(new CopyOnWriteArrayList<User>());
	}

	public static ConfirmMonitor getInstance() {
		synchronized (ConfirmMonitor.class) {
			if (instance == null) {
				instance = new ConfirmMonitor();
			}
		}
		return instance;
	}

	public void addBlockedUser(User user) {
		this.blockedUsers.add(user);
	}

	public void removeBlockedUser(User user) {
		this.blockedUsers.remove(user);
	}

	public boolean grantConfirm(User confirmer,
			ObjectManagementPool.GroupBidAuctionEntry groupBidAuction) {
		if (groupBidAuction == null) {
			return false;
		}
		if (groupBidAuction.getConfirmer1() != null
				&& groupBidAuction.getConfirmer2() == null) {
			return true;
		}

		double loggedInUsers = (double) ObjectManagementPool.getInstance()
				.getLoggedInUsers().size();

		// return false if only 2 logged in users, one would block on the other
		// and the other could not unlock himself -> deadlock
		if (loggedInUsers == 2) {
			return false;
		}

		if (variableFixed && groupBidAuction.getConfirmer1() == null) {

			double blockedusers = (double) this.blockedUsers.size();
			if (blockedusers / loggedInUsers >= variableDeadlockPercent) {
				return false;
			}
		} else if (!variableFixed && groupBidAuction.getConfirmer1() == null) {
			if (loggedInUsers - this.blockedUsers.size() - 1 < fixedNumOfUnblockedUsers) {
				return false;
			}
		}
		return true;
	}

	public void checkDeadlockAfterUserLogout() {
		if (ObjectManagementPool.getInstance().getLoggedInUsers().size() == this.blockedUsers
				.size()
				|| ObjectManagementPool.getInstance().getLoggedInUsers().size() == 2
				&& this.blockedUsers.size() == 1) {
			for (ObjectManagementPool.GroupBidAuctionEntry entry : ObjectManagementPool
					.getInstance().getGroupBidAuctions()) {
				if (entry.getConfirmer1() != null) {
					entry.getConfirmer1Channel()
							.println(
									"!rejected Other user logged out and therefor deadlock occured.");
				}
			}
		}
	}

}
